package com.lmaos.allcontrol.beancontrol.field_;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import com.lmaos.allcontrol.beancontrol.class_.ClassUtils;
/** 字段控制工具,通过反射操作方法,均为静态调用

 * @author lmaos 
 * 2016年11月14日 上午10:27:50
 */
public class FieldUtils {
	/** 字段缓存 初始时申请128长度,保证允许更多的线程同时访问
	 * 
	 */
	protected static Map<Class, Map<String,Field>> fieldCache = new ConcurrentHashMap<Class, Map<String,Field>>(128);
	private static Object FieldCacheLock = new Object();
	
	/** 添加字段的缓存
	 * 
	 * @param clazz
	 * @param field
	 * @param replace
	 */
	public static void addFieldCache(Class clazz,Field field){
		
		Map<String,Field> subFieldCache = fieldCache.get(clazz); // 获取这个子缓存
		if(subFieldCache == null){
			/* ********************************************** *
			 * 再此处同步,只允许一个线程进入操作.
			 * ********************************************** */
			synchronized (FieldCacheLock) {
				subFieldCache = fieldCache.get(clazz);				
				if(subFieldCache == null){						// 确定缓存不存在
					subFieldCache = new HashMap<String,Field>();// 创建缓存
					fieldCache.put(clazz, subFieldCache);
				}
			}
		}
		
		String key = field.getName();
		if(!subFieldCache.containsKey(key)){
			subFieldCache.put(key, field);
		}
	}
	
	/** 从缓存获取这个字段
	 * 
	 * @param clazz
	 * @param name
	 * @return
	 */
	protected static Field getFieldByCache(Class clazz,String name){
		Map<String,Field> subFieldCache = fieldCache.get(clazz); // 获取这个子缓存
		Field field = null;
		if(subFieldCache!=null){
			field = subFieldCache.get(name);
		}
		return field;
	}
	/** 从缓存获取这个类的字段集合
	 * 
	 * @param clazz
	 * @return
	 */
	protected static List<Field> getFieldsByCache(Class clazz){
		Map<String,Field> subFieldCache = fieldCache.get(clazz); // 获取这个子缓存
		List<Field> fields = new ArrayList<Field>();
		if(subFieldCache!=null){
			fields.addAll(subFieldCache.values());
		}
		return fields;
	}
	
	// 加载字段到同步锁,多线程时候线程安全
	protected final static Object loadFieldsLock = new Object();
	/** 加载全部都字段到缓存中。
	 * 
	 * @param clazz
	 */
	public static void loadAllFields(Class clazz,boolean replace){
		synchronized (loadFieldsLock) {
			
			/* *********************************************************** *
			 * 如果不存在当前缓存，则首先查询当前类所有继承的类。
			 * 得到所有继承的类后装载所有字段,会从子类一直加载到继承的父类上。
			 * *********************************************************** */
			if(!fieldCache.containsKey(clazz)){
				Map<String,Field> subFieldCache = new HashMap<String, Field>();
				List<Class> classs = ClassUtils.getClassAll(clazz, true);
				for (Class cl : classs) {
					Field[] fields = cl.getDeclaredFields();
					for (Field field : fields) {
						field.setAccessible(true); // 设置访问权限,设置为true 则可以对这个字段非法修改与访问
						String key = field.getName();
						if(!subFieldCache.containsKey(key)){
							subFieldCache.put(key, field);
						}
					}
				} // for-end
				fieldCache.put(clazz, subFieldCache);
			}else if(replace){ // 替换操作
				
				Map<String,Field> subFieldCache = new HashMap<String,Field>();
				
				List<Class> classs = ClassUtils.getClassAll(clazz, true);
				for (Class cl : classs) {
					Field[] fields = cl.getDeclaredFields();
					for (Field field : fields) {
						String key = field.getName();
						field.setAccessible(true); // 设置访问权限,设置为true 则可以对这个字段非法修改与访问
						subFieldCache.put(key, field);
					}
				} // for-end
				
				fieldCache.put(clazz, subFieldCache);	// 替换字段缓存
			}
		}
	}
	
	
	/** 加载全部都字段到缓存中。
	 * 
	 * @param clazz
	 */
	public static void loadAllFields(Class clazz){
		loadAllFields(clazz, false);
	}
	
	/** 获取字段
	 * 
	 * @param clazz
	 * @param name
	 * @return
	 */
	public static Field getField(Class clazz,String name){
		/* ********************************************** *
		 * 预先加载缓存,缓存存在时候直接从缓存读取字段
		 * ********************************************** */
		if(!fieldCache.containsKey(clazz)){
			loadAllFields(clazz);
		}
		
		Field field = getFieldByCache(clazz, name);
		return field;
	}
	
	/** 获取当前对象中这个字段当对象
	 * 
	 * @param obj
	 * @param name
	 * @return
	 */
	public static Field getField(Object obj,String name){
		Class clazz = obj.getClass();
		Field field = getField(clazz, name);
		return field;
	}
	
	public static List<Field> getFields(Object obj){
		return getFields(obj.getClass());
	}
	/** 获取全部都字段
	 * 
	 * @param clazz
	 * @return
	 */
	public static List<Field> getFields(Class clazz){
		/* ********************************************** *
		 * 预先加载缓存,缓存存在时候直接从缓存读取字段
		 * ********************************************** */
		if(!fieldCache.containsKey(clazz)){
			loadAllFields(clazz);
		}
		return getFieldsByCache(clazz);
	}
	public static Map<String, Field> getFieldsToMap(Object obj){
		return getFieldsToMap(obj.getClass());
	}
	
	/** 获取这些字段集合，map结构
	 * 
	 * @param clazz
	 * @return
	 */
	public static Map<String, Field> getFieldsToMap(Class clazz){
		if(!fieldCache.containsKey(clazz)){
			loadAllFields(clazz);
		}
		Map<String,Field> subFieldCache = fieldCache.get(clazz); // 获取这个子缓存
		if(subFieldCache==null){
			return new HashMap<String,Field>();
		}
		return new HashMap<String,Field>(subFieldCache);
	}
	
	/** 设置字段值,返回1设置成功,返回0类型错误，返回-1字段不存在
	 * 
	 * @param obj
	 * @param name
	 * @param value
	 * @return
	 */
	public static int setFieldValue(Object obj,String name,Object value){
		Field field = getField(obj, name);
		if(field == null){
			return -1;
		}
		try {
			field.set(obj, value);
			return 1;
		} catch (Exception e) {
			e.printStackTrace();
			return 0;
		}
	}
	public static int setFieldValue(Object obj,Field field,Object value){
		try {
			field.set(obj, value);
			return 1;
		} catch (Exception e) {
			e.printStackTrace();
			return 0;
		}
	}
	
	/** 读取当前字段当值
	 * 
	 * @param obj
	 * @param name
	 * @return
	 */
	public static <T>T getFieldValue(Object obj,String name){
		Field field = getField(obj, name);
		if(field == null){
			System.err.println("字段不存在:"+name);
			return null;
		}
		try {
			return (T) field.get(obj);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
	/** 查询被这些注解修饰到字段
	 * 
	 * @param clazz
	 * @param annotationClasss
	 * @return
	 */
	public static List<Field> indexFieldByAnnotation(Class clazz,Class... annotationClasss){
		if(annotationClasss == null || annotationClasss .length == 0){
			return getFields(clazz);
		}
		/* ****************************************************** *
		 * 结果集合储存查询的被这些注解修饰当字段。
		 * 先查询出所有字段，然后一条一条匹配注解。
		 * ***************************************************** */
		List<Field> cacheFields = getFields(clazz);
		List<Field> resultFields = new ArrayList<Field>();
		for (Field field : cacheFields) {
			// 查找匹配的字段
			for (Class annotationClass : annotationClasss) {
				if(field.isAnnotationPresent(annotationClass)){
					resultFields.add(field);
					break;
				}
			}
			
		}
		return resultFields;
	}
	/** 查询字段名称为指定名称开始的
	 * 
	 * @param clazz
	 * @param start
	 * @return
	 */
	public static List<Field> indexFieldByStartText(Class clazz,String start){
		if(start == null || start.isEmpty()){
			return getFields(clazz);
		}
		/* ****************************************************** *
		 * 结果集合储存查询的字段名为start开始。
		 * ***************************************************** */
		List<Field> cacheFields = getFields(clazz);
		List<Field> resultFields = new ArrayList<Field>();	// 结果
		for (Field field : cacheFields) {
			if(field.getName().startsWith(start)){
				resultFields.add(field);
			}
			
		}
		return resultFields;
	}
	
	/** 查询字段名称为指定名称结束的
	 * 
	 * @param clazz
	 * @param end
	 * @return
	 */
	public static List<Field> indexFieldByEndText(Class clazz,String end){
		if(end == null || end.isEmpty()){
			return getFields(clazz);
		}
		/* ****************************************************** *
		 * 结果集合储存查询的字段名为end结束。
		 * ***************************************************** */
		List<Field> cacheFields = getFields(clazz);
		List<Field> resultFields = new ArrayList<Field>();	// 结果
		for (Field field : cacheFields) {
			if(field.getName().endsWith(end)){
				resultFields.add(field);
			}
			
		}
		return resultFields;
	}
	
	/** 查询字段名称包含指定的内容的所有字段
	 * 
	 * @param clazz
	 * @param include 包含的内容
	 * @return
	 */
	public static List<Field> indexFieldByIncludeText(Class clazz,String include){
		if(include == null || include.isEmpty()){
			return getFields(clazz);
		}
		/* ****************************************************** *
		 * 结果集合储存查询的字段名包含include
		 * ***************************************************** */
		List<Field> cacheFields = getFields(clazz);			// 全部集合
		List<Field> resultFields = new ArrayList<Field>();	// 结果集合
		for (Field field : cacheFields) {
			if(field.getName().indexOf(include)!=-1){
				resultFields.add(field);
			}
			
		}
		return resultFields;
	}
	
}
